home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / common / ripple.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-01-15  |  21.8 KB  |  804 lines

  1. /* Ripple --- image filter plug-in for The Gimp image manipulation program
  2.  * Copyright (C) 1997 Brian Degenhardt
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  *
  18.  * Please direct all comments, questions, bug reports  etc to Brian Degenhardt
  19.  * bdegenha@ucsd.edu
  20.  *
  21.  * You can contact the original The Gimp authors at gimp@xcf.berkeley.edu
  22.  */
  23. #include "config.h"
  24.  
  25. #include <time.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28.  
  29. #include <gtk/gtk.h>
  30.  
  31. #include <libgimp/gimp.h>
  32. #include <libgimp/gimpui.h>
  33.  
  34. #include "libgimp/stdplugins-intl.h"
  35.  
  36.  
  37. /* Some useful macros */
  38. #define SCALE_WIDTH     200
  39. #define TILE_CACHE_SIZE  16
  40.  
  41. #define HORIZONTAL 0
  42. #define VERTICAL   1
  43.  
  44. #define SMEAR 0
  45. #define WRAP  1
  46. #define BLACK 2
  47.  
  48. #define SAWTOOTH 0
  49. #define SINE     1
  50.  
  51. typedef struct
  52. {
  53.   gint period;
  54.   gint amplitude;
  55.   gint orientation;
  56.   gint edges;
  57.   gint waveform;
  58.   gint antialias;
  59.   gint tile;
  60. } RippleValues;
  61.  
  62. typedef struct
  63. {
  64.   gint run;
  65. } RippleInterface;
  66.  
  67.  
  68. /* Declare local functions.
  69.  */
  70. static void    query  (void);
  71. static void    run    (gchar    *name,
  72.                gint      nparams,
  73.                GimpParam   *param,
  74.                gint     *nreturn_vals,
  75.                GimpParam  **return_vals);
  76.  
  77. static void    ripple             (GimpDrawable *drawable);
  78.  
  79. static gint    ripple_dialog      (void);
  80. static void    ripple_ok_callback (GtkWidget *widget,
  81.                    gpointer   data);
  82.  
  83. static GimpTile * ripple_pixel (GimpDrawable *drawable,
  84.                  GimpTile     *tile,
  85.                  gint        x1,
  86.                  gint        y1,
  87.                  gint        x2,
  88.                  gint        y2,
  89.                  gint        x,
  90.                  gint        y,
  91.                  gint       *row,
  92.                  gint       *col,
  93.                  guchar     *pixel);
  94.  
  95.  
  96. static gdouble displace_amount (gint     location);
  97. static guchar  averagetwo      (gdouble  location,
  98.                 guchar  *v);
  99. static guchar  averagefour     (gdouble  location,
  100.                 guchar  *v);
  101.  
  102. /***** Local vars *****/
  103.  
  104. GimpPlugInInfo PLUG_IN_INFO =
  105. {
  106.   NULL,  /* init_proc  */
  107.   NULL,  /* quit_proc  */
  108.   query, /* query_proc */
  109.   run,   /* run_proc   */
  110. };
  111.  
  112. static RippleValues rvals =
  113. {
  114.   20,         /* period      */
  115.   5,          /* amplitude   */
  116.   HORIZONTAL, /* orientation */
  117.   WRAP,       /* edges       */
  118.   SINE,       /* waveform    */
  119.   TRUE,       /* antialias   */
  120.   TRUE        /* tile        */
  121. };
  122.  
  123. static RippleInterface rpint =
  124. {
  125.   FALSE   /*  run  */
  126. };
  127.  
  128. /***** Functions *****/
  129.  
  130. MAIN ()
  131.  
  132. static void
  133. query (void)
  134. {
  135.   static GimpParamDef args[] =
  136.   {
  137.     { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  138.     { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
  139.     { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
  140.     { GIMP_PDB_INT32, "period", "period; number of pixels for one wave to complete" },
  141.     { GIMP_PDB_INT32, "amplitude", "amplitude; maximum displacement of wave" },
  142.     { GIMP_PDB_INT32, "orientation", "orientation; 0 = Horizontal, 1 = Vertical" },
  143.     { GIMP_PDB_INT32, "edges", "edges; 0 = smear, 1 =  wrap, 2 = black" },
  144.     { GIMP_PDB_INT32, "waveform", "0 = sawtooth, 1 = sine wave" },
  145.     { GIMP_PDB_INT32, "antialias", "antialias; True or False" },
  146.     { GIMP_PDB_INT32, "tile", "tile; if this is true, the image will retain it's tilability" }
  147.   };
  148.   static gint nargs = sizeof (args) / sizeof (args[0]);
  149.  
  150.   gimp_install_procedure ("plug_in_ripple",
  151.               "Ripple the contents of the specified drawable",
  152.               "Ripples the pixels of the specified drawable. Each row or column will be displaced a certain number of pixels coinciding with the given wave form",
  153.               "Brian Degenhardt <bdegenha@ucsd.edu>",
  154.               "Brian Degenhardt",
  155.               "1997",
  156.               N_("<Image>/Filters/Distorts/Ripple..."),
  157.               "RGB*, GRAY*",
  158.               GIMP_PLUGIN,
  159.               nargs, 0,
  160.               args, NULL);
  161. }
  162.  
  163. static void
  164. run (gchar  *name,
  165.      gint    nparams,
  166.      GimpParam  *param,
  167.      gint   *nreturn_vals,
  168.      GimpParam **return_vals)
  169. {
  170.   static GimpParam values[1];
  171.   GimpDrawable *drawable;
  172.   GimpRunModeType run_mode;
  173.   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  174.  
  175.   run_mode = param[0].data.d_int32;
  176.  
  177.   /*  Get the specified drawable  */
  178.   drawable = gimp_drawable_get (param[2].data.d_drawable);
  179.  
  180.   *nreturn_vals = 1;
  181.   *return_vals = values;
  182.  
  183.   values[0].type = GIMP_PDB_STATUS;
  184.   values[0].data.d_status = status;
  185.  
  186.   switch (run_mode)
  187.     {
  188.     case GIMP_RUN_INTERACTIVE:
  189.       INIT_I18N_UI();
  190.       /*  Possibly retrieve data  */
  191.       gimp_get_data ("plug_in_ripple", &rvals);
  192.  
  193.       /*  First acquire information with a dialog  */
  194.       if (! ripple_dialog ())
  195.     return;
  196.       break;
  197.  
  198.     case GIMP_RUN_NONINTERACTIVE:
  199.       INIT_I18N();
  200.       /*  Make sure all the arguments are there!  */
  201.       if (nparams != 10)
  202.     {
  203.       status = GIMP_PDB_CALLING_ERROR;
  204.     }
  205.       else
  206.     {
  207.       rvals.period = param[3].data.d_int32;
  208.       rvals.amplitude = param[4].data.d_int32;
  209.           rvals.orientation = (param[5].data.d_int32) ? VERTICAL : HORIZONTAL;
  210.           rvals.edges = (param[6].data.d_int32);
  211.           rvals.waveform = param[7].data.d_int32;
  212.           rvals.antialias = (param[8].data.d_int32) ? TRUE : FALSE;
  213.           rvals.tile = (param[9].data.d_int32) ? TRUE : FALSE;
  214.  
  215.       if (rvals.edges < SMEAR || rvals.edges > BLACK)
  216.         status = GIMP_PDB_CALLING_ERROR;
  217.     }
  218.       break;
  219.  
  220.     case GIMP_RUN_WITH_LAST_VALS:
  221.       INIT_I18N();
  222.       /*  Possibly retrieve data  */
  223.       gimp_get_data ("plug_in_ripple", &rvals);
  224.       break;
  225.  
  226.     default:
  227.       break;
  228.     }
  229.  
  230.   if (status == GIMP_PDB_SUCCESS)
  231.     {
  232.       /*  Make sure that the drawable is gray or RGB color  */
  233.       if (gimp_drawable_is_rgb (drawable->id) ||
  234.       gimp_drawable_is_gray (drawable->id))
  235.     {
  236.       gimp_progress_init ( _("Rippling..."));
  237.  
  238.       /*  set the tile cache size  */
  239.       gimp_tile_cache_ntiles (TILE_CACHE_SIZE);
  240.  
  241.       /*  run the ripple effect  */
  242.       ripple (drawable);
  243.  
  244.       if (run_mode != GIMP_RUN_NONINTERACTIVE)
  245.         gimp_displays_flush ();
  246.  
  247.       /*  Store data  */
  248.       if (run_mode == GIMP_RUN_INTERACTIVE)
  249.         gimp_set_data ("plug_in_ripple", &rvals, sizeof (RippleValues));
  250.     }
  251.       else
  252.     {
  253.       /* gimp_message ("ripple: cannot operate on indexed color images"); */
  254.       status = GIMP_PDB_EXECUTION_ERROR;
  255.     }
  256.     }
  257.  
  258.   values[0].data.d_status = status;
  259.  
  260.   gimp_drawable_detach (drawable);
  261. }
  262.  
  263. static void
  264. ripple (GimpDrawable *drawable)
  265. {
  266.   GimpPixelRgn dest_rgn;
  267.   GimpTile   * tile = NULL;
  268.   gint      row = -1;
  269.   gint      col = -1;
  270.   gpointer  pr;
  271.  
  272.   gint    width, height;
  273.   gint    bytes;
  274.   guchar *destline;
  275.   guchar *dest;
  276.   guchar *otherdest;
  277.   guchar  pixel[4][4];
  278.   gint    x1, y1, x2, y2;
  279.   gint    x, y;
  280.   gint    progress, max_progress;
  281.   gdouble needx, needy;
  282.  
  283.   guchar  values[4];
  284.   guchar  val;
  285.  
  286.   gint xi, yi;
  287.  
  288.   gint k;
  289.  
  290.   /* Get selection area */
  291.  
  292.   gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
  293.  
  294.   width  = drawable->width;
  295.   height = drawable->height;
  296.   bytes  = drawable->bpp;
  297.  
  298.   if ( rvals.tile )
  299.     {
  300.       rvals.edges = WRAP;
  301.       rvals.period = (width / (width / rvals.period) *
  302.               (rvals.orientation == HORIZONTAL) +
  303.               height / (height / rvals.period) *
  304.               (rvals.orientation == VERTICAL));
  305.     }
  306.  
  307.   progress     = 0;
  308.   max_progress = (x2 - x1) * (y2 - y1);
  309.  
  310.   /* Ripple the image.  It's a pretty simple algorithm.  If horizontal
  311.      is selected, then every row is displaced a number of pixels that
  312.      follows the pattern of the waveform selected.  The effect is
  313.      just reproduced with columns if vertical is selected.
  314.   */
  315.  
  316.   gimp_pixel_rgn_init (&dest_rgn, drawable,
  317.                x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
  318.   for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
  319.        pr != NULL;
  320.        pr = gimp_pixel_rgns_process (pr))
  321.     {
  322.       if (rvals.orientation == VERTICAL)
  323.     {
  324.           destline = dest_rgn.data;
  325.  
  326.           for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++)
  327.         {
  328.               dest = destline;
  329.  
  330.               for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++)
  331.         {
  332.                   otherdest = dest;
  333.  
  334.                   needy = y + displace_amount(x);
  335.                   yi = floor(needy);
  336.  
  337.           /* Tile the image. */
  338.                   if (rvals.edges == WRAP)
  339.             {
  340.                       needy = fmod(needy + height, height);
  341.                       yi = (yi + height) % height;
  342.             }
  343.           /* Smear out the edges of the image by repeating pixels. */
  344.                   else if (rvals.edges == SMEAR)
  345.             {
  346.                       if (yi < 0)
  347.             yi = 0;
  348.                       else if (yi > height - 1)
  349.             yi = height - 1;
  350.             }
  351.  
  352.                   if ( rvals.antialias)
  353.             {
  354.                       if (yi == height - 1)
  355.             {
  356.                           tile = ripple_pixel (drawable, tile,
  357.                            x1, y1, x2, y2,
  358.                            x, yi, &row, &col, pixel[0]);
  359.               
  360.                           for (k = 0; k < bytes; k++)
  361.                 *otherdest++ = pixel[0][k];
  362.             }
  363.                       else if (needy < 0 && needy > -1)
  364.             {
  365.                           tile = ripple_pixel (drawable, tile,
  366.                            x1, y1, x2, y2,
  367.                            x, 0, &row, &col, pixel[0]);
  368.  
  369.                           for (k = 0; k < bytes; k++)
  370.                 *otherdest++ = pixel[0][k];
  371.             }
  372.  
  373.                       else if (yi == height - 2 || yi == 0)
  374.             {
  375.                           tile = ripple_pixel (drawable, tile,
  376.                            x1, y1, x2, y2,
  377.                            x, yi, &row, &col, pixel[0]);
  378.                           tile = ripple_pixel (drawable, tile,
  379.                            x1, y1, x2, y2,
  380.                            x, yi + 1, &row, &col, pixel[1]);
  381.  
  382.                           for (k = 0; k < bytes; k++)
  383.                 {
  384.                               values[0] = pixel[0][k];
  385.                               values[1] = pixel[1][k];
  386.                               val = averagetwo(needy, values);
  387.  
  388.                               *otherdest++ = val;
  389.                 }
  390.             }
  391.                       else
  392.             {
  393.                           tile = ripple_pixel (drawable, tile,
  394.                            x1, y1, x2, y2,
  395.                            x, yi, &row, &col, pixel[0]);
  396.                           tile = ripple_pixel (drawable, tile,
  397.                            x1, y1, x2, y2,
  398.                            x, yi + 1, &row, &col, pixel[1]);
  399.                           tile = ripple_pixel (drawable, tile,
  400.                            x1, y1, x2, y2,
  401.                            x, yi - 1, &row, &col, pixel[2]);
  402.                           tile = ripple_pixel (drawable, tile,
  403.                            x1, y1, x2, y2,
  404.                            x, yi + 2, &row, &col, pixel[3]);
  405.  
  406.                           for (k = 0; k < bytes; k++)
  407.                 {
  408.                               values[0] = pixel[0][k];
  409.                               values[1] = pixel[1][k];
  410.                               values[2] = pixel[2][k];
  411.                               values[3] = pixel[3][k];
  412.  
  413.                               val = averagefour (needy, values);
  414.  
  415.                               *otherdest++ = val;
  416.                 }
  417.                       }
  418.             } /* antialias */
  419.                   else
  420.             {
  421.                       tile = ripple_pixel (drawable, tile,
  422.                        x1, y1, x2, y2,
  423.                        x, yi, &row, &col, pixel[0]);
  424.  
  425.                       for (k = 0; k < bytes; k++)
  426.             *otherdest++ = pixel[0][k];
  427.             }
  428.                   dest += dest_rgn.rowstride;
  429.         } /* for */
  430.  
  431.               for (k = 0; k < bytes; k++)
  432.         destline++;
  433.         } /* for */
  434.  
  435.           progress += dest_rgn.w * dest_rgn.h;
  436.           gimp_progress_update ((double) progress / (double) max_progress);
  437.     }
  438.       else /* HORIZONTAL */
  439.     {
  440.           destline = dest_rgn.data;
  441.  
  442.           for (y = dest_rgn.y; y < (dest_rgn.y + dest_rgn.h); y++)
  443.         {
  444.               dest = destline;
  445.  
  446.               for (x = dest_rgn.x; x < (dest_rgn.x + dest_rgn.w); x++)
  447.         {
  448.                   needx = x + displace_amount(y);
  449.                   xi = floor (needx);
  450.  
  451.           /* Tile the image. */
  452.                   if (rvals.edges == WRAP)
  453.             {
  454.                       needx = fmod((needx + width), width);
  455.                       xi = (xi + width) % width;
  456.             }
  457.           /* Smear out the edges of the image by repeating pixels. */
  458.                   else if (rvals.edges == SMEAR)
  459.             {
  460.                       if (xi < 0)
  461.             xi = 0;
  462.                       else if (xi > width - 1)
  463.             xi = width - 1;
  464.             }
  465.  
  466.                   if ( rvals.antialias)
  467.             {
  468.                       if (xi == width - 1)
  469.             {
  470.                           tile = ripple_pixel (drawable, tile,
  471.                            x1, y1, x2, y2,
  472.                            xi, y, &row, &col, pixel[0]);
  473.  
  474.                           for (k = 0; k < bytes; k++)
  475.                 *dest++ = pixel[0][k];
  476.             }
  477.                       else if (floor(needx) ==  -1)
  478.             {
  479.                           tile = ripple_pixel (drawable, tile,
  480.                            x1, y1, x2, y2,
  481.                            0, y, &row, &col, pixel[0]);
  482.  
  483.                           for (k = 0; k < bytes; k++)
  484.                 *dest++ = pixel[0][k];
  485.             }
  486.  
  487.                       else if (xi == width - 2 || xi == 0)
  488.             {
  489.                           tile = ripple_pixel (drawable, tile,
  490.                            x1, y1, x2, y2,
  491.                            xi, y, &row, &col, pixel[0]);
  492.                           tile = ripple_pixel (drawable, tile,
  493.                            x1, y1, x2, y2,
  494.                            xi + 1, y, &row, &col, pixel[1]);
  495.  
  496.                           for (k = 0; k < bytes; k++)
  497.                 {
  498.                               values[0] = pixel[0][k];
  499.                               values[1] = pixel[1][k];
  500.                               val = averagetwo (needx, values);
  501.  
  502.                               *dest++ = val;
  503.                 }
  504.             }
  505.                       else
  506.             {
  507.                           tile = ripple_pixel (drawable, tile,
  508.                            x1, y1, x2, y2,
  509.                            xi, y, &row, &col, pixel[0]);
  510.                           tile = ripple_pixel (drawable, tile,
  511.                            x1, y1, x2, y2,
  512.                            xi + 1, y, &row, &col, pixel[1]);
  513.                           tile = ripple_pixel (drawable, tile,
  514.                            x1, y1, x2, y2,
  515.                            xi - 1 , y, &row, &col, pixel[2]);
  516.                           tile = ripple_pixel (drawable, tile,
  517.                            x1, y1, x2, y2,
  518.                            xi + 2, y, &row, &col, pixel[3]);
  519.  
  520.                           for (k = 0; k < bytes; k++)
  521.                 {
  522.                               values[0] = pixel[0][k];
  523.                               values[1] = pixel[1][k];
  524.                               values[2] = pixel[2][k];
  525.                               values[3] = pixel[3][k];
  526.  
  527.                               val = averagefour (needx, values);
  528.  
  529.                               *dest++ = val;
  530.                 }
  531.             }
  532.             } /* antialias */
  533.  
  534.                   else
  535.             {
  536.                       tile = ripple_pixel (drawable, tile,
  537.                        x1, y1, x2, y2,
  538.                        xi, y, &row, &col, pixel[0]);
  539.  
  540.                       for (k = 0; k < bytes; k++)
  541.             *dest++ = pixel[0][k];
  542.             }
  543.         } /* for */
  544.  
  545.               destline += dest_rgn.rowstride;
  546.         } /* for */
  547.  
  548.           progress += dest_rgn.w * dest_rgn.h;
  549.           gimp_progress_update ((double) progress / (double) max_progress);
  550.     }
  551.     }  /* for  */
  552.  
  553.   if (tile)
  554.     gimp_tile_unref (tile, FALSE);
  555.  
  556.   /*  update the region  */
  557.   gimp_drawable_flush (drawable);
  558.   gimp_drawable_merge_shadow (drawable->id, TRUE);
  559.   gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
  560. } /* ripple */
  561.  
  562. static gint
  563. ripple_dialog (void)
  564. {
  565.   GtkWidget *dlg;
  566.   GtkWidget *toggle;
  567.   GtkWidget *toggle_vbox;
  568.   GtkWidget *main_vbox;
  569.   GtkWidget *frame;
  570.   GtkWidget *table;
  571.   GtkObject *scale_data;
  572.  
  573.   gimp_ui_init ("ripple", TRUE);
  574.  
  575.   dlg = gimp_dialog_new (_("Ripple"), "ripple",
  576.              gimp_standard_help_func, "filters/ripple.html",
  577.              GTK_WIN_POS_MOUSE,
  578.              FALSE, TRUE, FALSE,
  579.  
  580.              _("OK"), ripple_ok_callback,
  581.              NULL, NULL, NULL, TRUE, FALSE,
  582.              _("Cancel"), gtk_widget_destroy,
  583.              NULL, 1, NULL, FALSE, TRUE,
  584.  
  585.              NULL);
  586.  
  587.   gtk_signal_connect (GTK_OBJECT (dlg), "destroy",
  588.               GTK_SIGNAL_FUNC (gtk_main_quit),
  589.               NULL);
  590.  
  591.   /*  The main vbox  */
  592.   main_vbox = gtk_vbox_new (FALSE, 6);
  593.   gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6);
  594.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), main_vbox,
  595.               FALSE, FALSE, 0);
  596.  
  597.   /* The table to hold the four frames of options */
  598.   table = gtk_table_new (2, 2, FALSE);
  599.   gtk_table_set_col_spacings (GTK_TABLE (table), 6);
  600.   gtk_table_set_row_spacings (GTK_TABLE (table), 6);
  601.   gtk_box_pack_start (GTK_BOX (main_vbox), table, FALSE, FALSE, 0);
  602.  
  603.   /*  Options section  */
  604.   frame = gtk_frame_new ( _("Options"));
  605.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  606.   gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1,
  607.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  608.  
  609.   toggle_vbox = gtk_vbox_new (FALSE, 1);
  610.   gtk_container_set_border_width (GTK_CONTAINER (toggle_vbox), 2);
  611.   gtk_container_add (GTK_CONTAINER (frame), toggle_vbox);
  612.  
  613.   toggle = gtk_check_button_new_with_label (_("Antialiasing"));
  614.   gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0);
  615.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  616.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  617.               &rvals.antialias);
  618.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), rvals.antialias);
  619.   gtk_widget_show (toggle);
  620.  
  621.   toggle = gtk_check_button_new_with_label ( _("Retain Tilability"));
  622.   gtk_box_pack_start (GTK_BOX (toggle_vbox), toggle, FALSE, FALSE, 0);
  623.   gtk_signal_connect (GTK_OBJECT (toggle), "toggled",
  624.               GTK_SIGNAL_FUNC (gimp_toggle_button_update),
  625.               &rvals.tile);
  626.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle), (rvals.tile));
  627.   gtk_widget_show (toggle);
  628.  
  629.   gtk_widget_show (toggle_vbox);
  630.   gtk_widget_show (frame);
  631.  
  632.   /*  Orientation toggle box  */
  633.   frame =
  634.     gimp_radio_group_new2 (TRUE, _("Orientation"),
  635.                gimp_radio_button_update,
  636.                &rvals.orientation, GINT_TO_POINTER (rvals.orientation),
  637.  
  638.                _("Horizontal"), GINT_TO_POINTER (HORIZONTAL), NULL,
  639.                _("Vertical"),   GINT_TO_POINTER (VERTICAL), NULL,
  640.  
  641.                NULL);
  642.   gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1,
  643.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  644.   gtk_widget_show (frame);
  645.  
  646.   /*  Edges toggle box  */
  647.   frame = gimp_radio_group_new2 (TRUE, _("Edges"),
  648.                  gimp_radio_button_update,
  649.                  &rvals.edges, GINT_TO_POINTER (rvals.edges),
  650.  
  651.                  _("Wrap"),  GINT_TO_POINTER (WRAP), NULL,
  652.                  _("Smear"), GINT_TO_POINTER (SMEAR), NULL,
  653.                  _("Black"), GINT_TO_POINTER (BLACK), NULL,
  654.  
  655.                  NULL);
  656.   gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 1, 2,
  657.             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  658.   gtk_widget_show (frame);
  659.  
  660.   /*  Wave toggle box  */
  661.   frame = gimp_radio_group_new2 (TRUE, _("Wave Type"),
  662.                  gimp_radio_button_update,
  663.                  &rvals.waveform, GINT_TO_POINTER (rvals.waveform),
  664.  
  665.                  _("Sawtooth"), GINT_TO_POINTER (SAWTOOTH), NULL,
  666.                  _("Sine"),     GINT_TO_POINTER (SINE), NULL,
  667.  
  668.                  NULL);
  669.   gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 1, 2,
  670.             GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
  671.   gtk_widget_show (frame);
  672.  
  673.   gtk_widget_show (table);
  674.  
  675.   /*  Parameter Settings  */
  676.   frame = gtk_frame_new ( _("Parameter Settings"));
  677.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  678.   gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
  679.  
  680.   table = gtk_table_new (2, 3, FALSE);
  681.   gtk_table_set_col_spacings (GTK_TABLE (table), 4);
  682.   gtk_table_set_row_spacings (GTK_TABLE (table), 2);
  683.   gtk_container_set_border_width (GTK_CONTAINER (table), 4);
  684.   gtk_container_add (GTK_CONTAINER (frame), table);
  685.  
  686.   /*  Period  */
  687.   scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 0,
  688.                      _("Period:"), SCALE_WIDTH, 0,
  689.                      rvals.period, 0, 200, 1, 10, 0,
  690.                      TRUE, 0, 0,
  691.                      NULL, NULL);
  692.   gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
  693.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  694.               &rvals.period);
  695.  
  696.   /*  Amplitude  */
  697.   scale_data = gimp_scale_entry_new (GTK_TABLE (table), 0, 1,
  698.                      _("Amplitude:"), SCALE_WIDTH, 0,
  699.                      rvals.amplitude, 0, 200, 1, 10, 0,
  700.                      TRUE, 0, 0,
  701.                      NULL, NULL);
  702.   gtk_signal_connect (GTK_OBJECT (scale_data), "value_changed",
  703.               GTK_SIGNAL_FUNC (gimp_int_adjustment_update),
  704.               &rvals.amplitude);
  705.  
  706.   gtk_widget_show (frame);
  707.   gtk_widget_show (table);
  708.  
  709.   gtk_widget_show (main_vbox);
  710.   gtk_widget_show (dlg);
  711.  
  712.   gtk_main ();
  713.   gdk_flush ();
  714.  
  715.   return rpint.run;
  716. }
  717.  
  718. static GimpTile *
  719. ripple_pixel (GimpDrawable *drawable,
  720.           GimpTile     *tile,
  721.           gint       x1,
  722.           gint       y1,
  723.           gint       x2,
  724.           gint       y2,
  725.           gint       x,
  726.           gint       y,
  727.           gint      *row,
  728.           gint      *col,
  729.           guchar    *pixel)
  730. {
  731.   static guchar empty_pixel[4] = {0, 0, 0, 0};
  732.  
  733.   guchar *data;
  734.   gint    b;
  735.  
  736.   if (x >= x1 && y >= y1 && x < x2 && y < y2)
  737.     {
  738.       if ((x >> 6 != *col) || (y >> 6 != *row))
  739.     {
  740.       *col = x / 64;
  741.       *row = y / 64;
  742.       if (tile)
  743.         gimp_tile_unref (tile, FALSE);
  744.       tile = gimp_drawable_get_tile (drawable, FALSE, *row, *col);
  745.       gimp_tile_ref (tile);
  746.     }
  747.  
  748.       data = tile->data + tile->bpp * (tile->ewidth * (y % 64) + (x % 64));
  749.     }
  750.   else
  751.     data = empty_pixel;
  752.  
  753.   for (b = 0; b < drawable->bpp; b++)
  754.     pixel[b] = data[b];
  755.  
  756.   return tile;
  757. }
  758.  
  759.  
  760. /*  Ripple interface functions  */
  761.  
  762. static void
  763. ripple_ok_callback (GtkWidget *widget,
  764.             gpointer   data)
  765. {
  766.   rpint.run = TRUE;
  767.  
  768.   gtk_widget_destroy (GTK_WIDGET (data));
  769. }
  770.  
  771. static guchar
  772. averagetwo (gdouble  location,
  773.         guchar  *v)
  774. {
  775.   location = fmod(location, 1.0);
  776.  
  777.   return (guchar) ((1.0 - location) * v[0] + location * v[1]);
  778. }
  779.  
  780. static guchar
  781. averagefour (gdouble  location,
  782.          guchar  *v)
  783. {
  784.   location = fmod(location, 1.0);
  785.  
  786.   return ((1.0 - location) * (v[0] + v[2]) + location * (v[1] + v[3]))/2;
  787. }
  788.  
  789. static gdouble
  790. displace_amount (gint location)
  791. {
  792.   switch (rvals.waveform)
  793.     {
  794.     case SINE:
  795.       return rvals.amplitude*sin(location*(2*G_PI)/(double)rvals.period);
  796.     case SAWTOOTH:
  797.       return floor (rvals.amplitude *
  798.             (fabs ((((location%rvals.period) /
  799.                  (double)rvals.period) * 4) - 2) - 1));
  800.     }
  801.  
  802.   return 0;
  803. }
  804.